package basis.threadpool;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadPool {
    private int size;

    private List<ThreadInPool> threads = new ArrayList<>();

    private Queue<Task> tasks = new LinkedList<>();

    private Lock taskLock = new ReentrantLock();

    // 对condition的操作，必然是在持有锁的前提之下
    // 即只能在同步代码块中进行同步操作
    private Condition tasksNotEmpty = taskLock.newCondition();

    public ThreadPool(int size) {
        this.size = size;
        ThreadInPool t;
        for (int i = 0; i < size; ++i) {
            threads.add(t = new ThreadInPool());
            t.start();  // 创建线程
            System.out.println(t.getName() + "-启动完成");
        }
    }

    // 在使用线程间通信时，必须先持有锁，即在同步块内才能进行线程通信
    // 否则会有 IllegalMonitorStateException
    public void execute(Runnable work) {
        final Lock lock = taskLock;
        lock.lock();
        try {
            tasks.offer(new Task(work));
            tasksNotEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    private class ThreadInPool extends Thread {
        // 线程要执行的工作
        @Override
        public void run() {
            final Lock lock = taskLock;
            for (;;) {
                lock.lock();
                try {
                    while (tasks.isEmpty())
                        tasksNotEmpty.await();
                    // 每一个线程的工作就是从任务队列中取出任务执行
                    tasks.poll().run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}

